package easy.netty.net.rpc;

import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;

/**
 * @author cengy
 */
public class RpcFuture<T> {

    public final static int STATE_AWAIT = 0;
    public final static int STATE_SUCCESS = 1;
    public final static int STATE_EXCEPTION = 2;
    public final static int STATE_CANCEL = 3;

    private CountDownLatch countDownLatch;
    private T result;
    private Throwable throwable;
    private int state;

    public RpcFuture() {
        countDownLatch = new CountDownLatch(1);
        state = STATE_AWAIT;
    }

    public T get() throws Throwable {
        return get(10 * 1000);
    }

    public T get(long timeoutMs) throws Throwable {
        if (timeoutMs <= 0 || timeoutMs > Integer.MAX_VALUE)
            timeoutMs = 10 * 1000;
        boolean awaitSuccess = true;

        boolean broken = false; // 等待过程被终止
        try {
            awaitSuccess = countDownLatch.await(timeoutMs, TimeUnit.MILLISECONDS);
        } catch (InterruptedException e) {
            // ignore
            broken = true;
        }

        if (!awaitSuccess && !broken) {
            throw new RuntimeException("rpc call timeout " + timeoutMs);
        }

        if (broken) {
            // how to do ?
            state = STATE_CANCEL;
        }

        if (state == STATE_SUCCESS) {
            return result;
        } else if (state == STATE_EXCEPTION) {
            throw throwable;
        } else if (state == STATE_EXCEPTION) {
            throw new RpcCancelException("Rpc call cancel");
        } else {
            throw new RuntimeException("RpcFuture exception");
        }
    }

    public void cancel() {
        state = STATE_CANCEL;
        countDownLatch.countDown();
    }

    public void setResult(Object result) {
        this.result = (T) result;
        state = STATE_SUCCESS;

        countDownLatch.countDown();

    }

    public void setThrowable(Throwable throwable) {
        this.throwable = throwable;
        state = STATE_EXCEPTION;

        countDownLatch.countDown();
    }

}
